// 路由注册工具，增强 Express Router 实例，支持单行注册并自动注入操作日志元数据
// 
// 【用法示例】
// import { createController } from '@/utils/router/route.controller';
// const router = createController(Router());
// // 注册路由（推荐使用 GET/POST/PUT/DELETE/PATCH 方法）
// router.GET('/list', loginInfoController.list, [auth, perm]);
// router.POST('/add', loginInfoController.add, [auth]);
// // 也可以继续使用 router.get/post/put/delete/patch 原生 Express 方法注册普通路由
// export default router;
//
// 【说明】
// - createController 返回的 router 既是 Express Router 实例，也拥有 GET/POST/PUT/DELETE/PATCH 方法
// - 推荐用 GET/POST/PUT/DELETE/PATCH 方法注册需要自动注入操作日志元数据的路由
// - GET/POST/PUT/DELETE/PATCH 方法参数：(path, handler, middleware?)，handler 必须为具名函数
// - 其他普通路由可继续用 router.get/post/put/delete/patch 等 Express 原生方法注册
// - 导出 router 即可被 Express 识别
//
// 自动注入日志元数据：req.route = { controller, methodName }，配合@Log装饰器实现操作日志自动记录

import { Router, Request, Response, NextFunction, RequestHandler } from 'express';
import { getRepeatSubmitMetadata } from '@/decorators/repeatSubmit.decorator';
import { getRateLimitMetadata } from '@/decorators/rateLimit.decorator';
import { repeatSubmitMiddleware, rateLimitMiddleware } from '@/middlewares/common.middleware';

type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch';

type Register = (path: string, ...handlers: RequestHandler[]) => void;

// 增强型 Router 类型，支持 GET/POST/PUT/DELETE/PATCH
export interface EnhancedRouter extends Router {
  GET: Register;
  POST: Register;
  PUT: Register;
  DELETE: Register;
  PATCH: Register;
}

/**
 * 路由注册工具，增强 Express Router 实例，支持单行注册并自动注入操作日志元数据
 * - 推荐用 GET/POST/PUT/DELETE/PATCH 方法注册需要自动注入操作日志元数据的路由
 * - 其他普通路由可继续用 router.get/post/put/delete/patch 等 Express 原生方法注册
 * - 只支持对象方法单行注册，不支持链式注册
 * @param router Express Router
 * @returns 挂载了 GET/POST/PUT/DELETE/PATCH 的 Router 实例
 */
export function createController(router: Router): EnhancedRouter {
  function reg(method: HttpMethod): Register {
    // 定义并返回一个路由注册函数，接收路径和处理器参数
    return (path, ...handlers) => {
      // 检查是否提供了处理器，如果没有则抛出错误
      if (handlers.length === 0) throw new Error('必须传递控制器方法');
      // 获取最后一个参数作为控制器处理方法
      const handler = handlers[handlers.length - 1];
      // 获取处理器方法名，用于元数据查找和日志记录
      const methodName = handler.name;
      // 确保处理器是具名函数，匿名函数无法获取方法名，导致无法正确记录日志
      if (!methodName) throw new Error('控制器方法必须具名，不能是匿名函数');
      // 除了最后一个处理器外，其余都视为中间件
      const middlewares = handlers.slice(0, -1);
      // 初始化自动注入的中间件数组，用于防重提交和限流等功能
      const autoMiddlewares: RequestHandler[] = [];
      // 获取处理器上的防重提交元数据（通过@RepeatSubmit装饰器设置）
      const repeatSubmitMeta = getRepeatSubmitMetadata(handler);
      // 如果存在防重提交元数据，则添加防重提交中间件
      if (repeatSubmitMeta) {
        // 将防重提交中间件添加到自动中间件数组，传入过期时间参数
        autoMiddlewares.push(repeatSubmitMiddleware(repeatSubmitMeta.expireSeconds));
      }
      // 获取处理器上的限流元数据（通过@RateLimit装饰器设置）
      const rateLimitMeta = getRateLimitMetadata(handler);
      // 如果存在限流元数据，则添加限流中间件
      if (rateLimitMeta) {
        // 将限流中间件添加到自动中间件数组，传入限制次数和时间窗口参数
        autoMiddlewares.push(rateLimitMiddleware(rateLimitMeta.limit, rateLimitMeta.windowSeconds));
      }
      // 创建包装处理器，用于注入路由元数据和错误处理
      const wrapped = async (req: Request, res: Response, next: NextFunction) => {
        // 向请求对象注入路由元数据，包括控制器方法和方法名，供操作日志中间件使用
        // 使用routeMeta属性代替route属性，避免与Express原生属性冲突
        (req as any).routeMeta = {controller: handler, methodName};
        try {
          // 异步调用控制器方法，传入请求、响应和下一个中间件
          await handler(req, res, next);
        } catch (err) {
          // 如果控制器方法执行出错，则传递错误到下一个错误处理中间件
          next(err);
        }
      };
      // 注册路由，按顺序添加自动中间件、用户中间件和包装后的控制器方法
      (router as any)[method](path, ...autoMiddlewares, ...middlewares, wrapped);
    };
  }
  // 挂载注册方法到 router 实例上
  (router as any).GET = reg('get');
  (router as any).POST = reg('post');
  (router as any).PUT = reg('put');
  (router as any).DELETE = reg('delete');
  (router as any).PATCH = reg('patch');
  return router as EnhancedRouter;
}
